import requests
import os
import json
import time


class QQMusic:
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36',
        'Referer': 'https://y.qq.com/'
    }
    TIMEOUT = 10
    # 可以在这里设置代理，目前为空，需要时修改
    proxies = {}

    def __init__(self):
        self.ensure_music_folder()

    def ensure_music_folder(self):
        try:
            if not os.path.exists("./music"):
                os.mkdir("./music")
        except OSError as e:
            print(f"创建音乐文件夹时出错: {e}")

    def get_request(self, url):
        try:
            response = requests.get(url, headers=self.headers, timeout=self.TIMEOUT, proxies=self.proxies)
            if response.status_code == 200:
                return response
            else:
                print(f"请求失败，状态码: {response.status_code}")
                return None
        except requests.Timeout:
            print("网络请求超时，请重新下载")
            return None
        except requests.RequestException as e:
            print(f"请求出错: {e}")
            return None

    def download(self, data, song_name):
        save_path = os.path.join("music", f"{song_name}.m4a")
        try:
            print("下载中.....")
            with open(save_path, 'wb') as f:
                f.write(data)
            print(f"{song_name}已下载至{os.path.abspath(save_path)}")
        except OSError as e:
            print(f"文件写入出错: {e}")

    def search_songs(self, song_name):
        url1 = f'https://c.y.qq.com/soso/fcgi-bin/client_search_cp?&t=0&aggr=1&cr=1&catZhida=1&lossless=0&flag_qc=0&p=1&n=20&w={song_name}'
        response = self.get_request(url1)
        time.sleep(1)
        if not response:
            return [], [], [], []
        try:
            data = json.loads(response.text.strip('callback()[]'))
            song_list = data['data']['song']['list']
            medias = []
            song_mids = []
            song_names = []
            singers = []
            for song in song_list:
                try:
                    medias.append(song['media_mid'])
                    song_mids.append(song['songmid'])
                    song_names.append(song['songname'])
                    singers.append(song['singer'][0]['name'])
                except KeyError:
                    print('检测到错误，资源可能与您预期不符')
            return medias, song_mids, song_names, singers
        except (KeyError, json.JSONDecodeError) as e:
            print(f"解析搜索结果出错: {e}")
            return [], [], [], []

    def get_song_urls(self, medias, song_mids):
        src = []
        for media, song_mid in zip(medias, song_mids):
            url2 = f'https://c.y.qq.com/base/fcgi-bin/fcg_music_express_mobile3.fcg?&jsonpCallback=MusicJsonCallback&cid=205361747&songmid={song_mid}&filename=C400{media}.m4a&guid=6612300644'
            response = self.get_request(url2)
            time.sleep(1)
            if not response:
                continue
            try:
                data = json.loads(response.text)
                vkey = data['data']['items'][0]['vkey']
                src.append(
                    f'http://dl.stream.qqmusic.qq.com/C400{media}.m4a?vkey={vkey}&guid=6612300644&uin=0&fromtag=66')
            except (KeyError, json.JSONDecodeError) as e:
                print(f"解析歌曲链接出错: {e}")
        return src

    def qq_music_api(self):
        print("\n", "{:^30}".format("正在使用QQ音乐VIP下载器"))
        while True:
            song_name = input("\n请输入歌名>>").strip()
            if not song_name:
                continue
            if song_name == 'q':
                print("退出QQ音乐下载")
                break
            print("正在努力寻找资源.........")
            medias, song_mids, song_names, singers = self.search_songs(song_name)
            src = self.get_song_urls(medias, song_mids)
            if not src:
                print("未找到相关歌曲，请重新输入")
                continue
            print("为你找到以下内容".center(30, '*'))
            print("序号      ", "歌手    -     歌名")
            for i, (song_name, singer) in enumerate(zip(song_names, singers), start=1):
                print(f"{i}    {song_name} - {singer}.m4a")
            while True:
                try:
                    song_index = int(input("请选择序号>>").strip())
                    if song_index < 1 or song_index > len(src):
                        print("输入的序号无效，请重新输入")
                        continue
                    break
                except ValueError:
                    print("输入的不是有效的数字，请重新输入")
            song_data = self.get_request(src[song_index - 1])
            if song_data is not None:
                self.download(song_data.content, song_names[song_index - 1])
            else:
                print(f"无法获取歌曲 {song_names[song_index - 1]} 的数据，请检查网络或重试。")


if __name__ == '__main__':
    qq_API = QQMusic()
    print("{:^30}".format("欢迎使用VIP音乐破解"))
    qq_API.qq_music_api()
